package collector

import (
	"encoding/json"
	"errors"
	"fmt"
	"github.com/didi/nightingale/src/models"
	"github.com/didi/nightingale/src/modules/monapi/collector"
	"github.com/influxdata/telegraf"
)

func init() {
	collector.CollectorRegister(&ServiceCollector{})
}

type ServiceCollector struct{}

func (s ServiceCollector) Name() string                   { return "service" }
func (s ServiceCollector) Category() collector.Category   { return collector.LocalCategory }
func (s ServiceCollector) Template() (interface{}, error) { return nil, nil }
func (s ServiceCollector) TelegrafInput(*models.CollectRule) (telegraf.Input, error) {
	return nil, errors.New("unsupported")
}

func (s ServiceCollector) Get(id int64) (interface{}, error) {
	collect := new(models.ServiceCollectRes)
	has, err := models.DB["mon"].SQL("select sc.*, t1.rely_ids, t1.rely_names from service_collect sc left join (select source_id, "+
		"GROUP_CONCAT(sc2.id) as rely_ids, GROUP_CONCAT(sc2.name) as rely_names from service_topu st, service_collect sc2 "+
		"where st.target_id =sc2.id and st.source_id=? group by st.source_id) as t1 on sc.id=t1.source_id where sc.id=?", id, id).Get(collect)
	if !has {
		return nil, err
	}
	strees := []*models.StreeDiscovery{}
	err = models.DB["mon"].Where("service_id=?", id).Find(&strees)
	if err != nil {
		return nil, err
	}
	collect.Strees = strees
	lvses := []*models.LvsDiscovery{}
	err = models.DB["mon"].Where("service_id=?", id).Find(&lvses)
	if err != nil {
		return nil, err
	}
	collect.Lvses = lvses
	starks := []*models.StarkDiscovery{}
	err = models.DB["mon"].Where("service_id=?", id).Find(&starks)
	if err != nil {
		return nil, err
	}
	collect.Starks = starks
	manuals := []*models.ManualDiscovery{}
	err = models.DB["mon"].Where("service_id=?", id).Find(&manuals)
	if err != nil {
		return nil, err
	}
	collect.Manuals = manuals
	urls := []*models.UrlDiscovery{}
	err = models.DB["mon"].Where("service_id=?", id).Find(&urls)
	if err != nil {
		return nil, err
	}
	collect.Urls = urls
	return collect, err
}

func (s ServiceCollector) Gets(nids []int64) (ret []interface{}, err error) {
	collects := []models.ServiceCollectRes{}
	if len(nids) == 0 {
		sql := "select sc.*, t1.rely_ids, t1.rely_names from service_collect sc left join (select source_id, " +
			"GROUP_CONCAT(sc2.id) as rely_ids, GROUP_CONCAT(sc2.name) as rely_names from service_topu st, service_collect " +
			"sc2 where st.target_id =sc2.id group by st.source_id) as t1 on sc.id=t1.source_id"
		err = models.DB["mon"].SQL(sql).Find(&collects)

	} else {
		sql := "select sc.*, t1.rely_ids, t1.rely_names from service_collect sc left join (select source_id, " +
			"GROUP_CONCAT(sc2.id) as rely_ids, GROUP_CONCAT(sc2.name) as rely_names from service_topu st, service_collect " +
			"sc2 where st.target_id =sc2.id group by st.source_id) as t1 on sc.id=t1.source_id where sc.nid in (%s)"
		params, idStr := formatids(nids)
		sql = fmt.Sprintf(sql, idStr)
		err = models.DB["mon"].SQL(sql, params...).Find(&collects)
	}
	for _, c := range collects {
		ret = append(ret, c)
	}
	return ret, err
}

func (s ServiceCollector) GetByNameAndNid(name string, nid int64) (interface{}, error) {
	collect := new(models.ServiceCollect)
	has, err := models.DB["mon"].Where("name=? and nid=?", name, nid).Get(collect)
	if !has {
		return nil, err
	}
	return collect, err
}

func (s ServiceCollector) Create(data []byte, username string) error {
	collect := new(models.ServiceCollect)

	err := json.Unmarshal(data, collect)
	if err != nil {
		return fmt.Errorf("unmarshal body %s err:%v", string(data), err)
	}

	can, err := models.UsernameCandoNodeOp(username, "mon_collect_create", collect.Nid)
	if err != nil {
		return err
	}
	if !can {
		return fmt.Errorf("permission deny")
	}

	collect.Creator = username
	collect.LastUpdator = username

	nid := collect.Nid
	name := collect.Name

	old, err := s.GetByNameAndNid(name, nid)
	if err != nil {
		return err
	}
	if old != nil {
		return fmt.Errorf("同节点下策略名称 %s 已存在", name)
	}
	return collect.Create(s.Name())
}

func (s ServiceCollector) Update(data []byte, username string) error {
	collect := new(models.ServiceCollect)

	err := json.Unmarshal(data, collect)
	if err != nil {
		return fmt.Errorf("unmarshal body %s err:%v", string(data), err)
	}

	can, err := models.UsernameCandoNodeOp(username, "mon_collect_modify", collect.Nid)
	if err != nil {
		return err
	}
	if !can {
		return fmt.Errorf("permission deny")
	}

	nid := collect.Nid
	name := collect.Name

	//校验采集是否存在
	obj, err := s.Get(collect.Id) //id找不到的情况
	if err != nil {
		return fmt.Errorf("采集不存在 type:%s id:%d", s.Name(), collect.Id)
	}

	tmpId := obj.(*models.ServiceCollectRes).Id
	if tmpId == 0 {
		return fmt.Errorf("采集不存在 type:%s id:%d", s.Name(), collect.Id)
	}

	collect.LastUpdator = username

	old, err := s.GetByNameAndNid(name, nid)
	if err != nil {
		return err
	}
	if old != nil && tmpId != old.(*models.ServiceCollect).Id {
		return fmt.Errorf("同节点下策略名称 %s 已存在", name)
	}

	return collect.Update()
}

func (s ServiceCollector) Delete(id int64, username string) error {
	collect := new(models.ServiceCollect)
	tmp, err := s.Get(id) //id找不到的情况
	if err != nil {
		return fmt.Errorf("采集不存在 type:%s id:%d", s.Name(), id)
	}
	nid := tmp.(*models.ServiceCollectRes).Nid
	can, err := models.UsernameCandoNodeOp(username, "mon_collect_delete", int64(nid))
	if err != nil {
		return err
	}
	if !can {
		return fmt.Errorf("permission deny")
	}

	return collect.Delete(id, username)
}

func formatids(ids []int64) ([]interface{}, string) {
	inIds := ""
	params := make([]interface{}, 0)
	for i := 0; i < len(ids); i++ {
		if i == 0 {
			inIds += "?"
		} else {
			inIds += ",?"
		}
		params = append(params, ids[i])
	}
	return params, inIds
}
